iT邦幫忙

2025 iThome 鐵人賽

DAY 7
0

今日內容:繼承(inheritance)、super、override、toString()、抽象(abstraction)、介面(interface)


繼承(inheritance)

過去在C++中是使用 ":" 進行繼承

public class Dog : public Animal{
    // ...
}

而Java使用的是 extends 這個關鍵字

// 首先宣告Animal這個parent class (base class)
public class Animal{
    boolean isAlive;
    Animal(){
        isAlive = true;
    }
    void eat(){
        System.out.println("The animal is eating");
    }
}

// 接著宣告Dog去extends Animal,Dog是subclass (derived class)
public class Dog extends Animal{
    void speak(){
        System.out.println("The dog goes *woof*");
    }
}

// Cat也是一樣的道理
public class Cat extends Animal{
    void speak(){
        System.out.println("The cat goes *meow*")
    }
}

這樣宣告出來的Dog或Cat函式都屬於Animal的subclass
而這麼做的目的就是為了之後的polymorphism,或者是方便進行管理、理解


super

super這個關鍵字用於subclass的constructor中
需要用super將資料傳回給parent class,才能正常宣告

public class Person{
    String first;
    String last;
    Person(String first, String last){
        this.first = first;
        this.last = last;
    }
    void showName(){
        System.out.printf("%s %s\n", this.first, this.last);
    }
}

public class Student extends Person{
    double gpa;
    Student(String first, String last, double gpa){
        super(first, last); // 系統會根據繼承的parent class自動去找資料,建構回去
        this.gpa = gpa;
    }
}

override

對於subclass可以讓他對同一個名稱的函式執行與parent class不一樣的操作

public class Animal{
    void move(){
        System.out.println("The animal is moving");
    }
}

public class Fish extends Animal{
    // 由於魚是swim不是run
    
    @Override // 這邊加上 @Override 關鍵字,用意是提高程式可讀性,且compiler也可以幫忙進行檢查
    void move(){
        System.out.println("The anime is swimming");
    }
}

toString()

Java的class都會有一個成員函式叫做toString(),而他是可以被override的
正常來說,我們println()一個物件,他會回傳這個物件的hash值
由於還沒開始學習資料結構,我還不了解hash和hash table實際上是在做甚麼,先暫時知道怎麼用就好

我們可以在自己宣告的class裡面對toString() override,就可以讓他輸出有意義的值(可以自己設定想看到的內容)

public class Car{
    String make, model;
    int year;
    
    // ...
    
    @Override
    public String toString(){
        return this.year + " " + this.make + " " + this.model;
        // 回傳的型態是String,這邊使用 + 將資料組合成一個String,然後回傳
    }
}

// 這樣當我們println(car),就會顯示對應的年份車種了

抽象(abstraction)

在class前面加關鍵字abstract,可以讓整個class變成抽象類別(不能被宣告出物件)
在method前面加abstract,也可以讓那個東西變成必須被subclass定義的內容

public abstract class Shape{
    abstract double area(); // abstract method不須給予實作定義(implementation)
    void display(){System.out.println("This is a shape");} // abstract class裡面也可以有非abstract的內容
}

// 使用extends進行繼承
public class Circle extends Shape{
    double radius;
    Circle(double radius){
        this.radius = radius;
    }
    
    // 需要override area這個函式(所有abstract methods)才可以使這個class變得concrete,才能宣告出物件
    @Override
    double area(){return Math.PI * radius * radius}
}

public class Triangle extends Shape{
    double base, height;
    Triangle(double base, double height){
        this.base = base;
        this.height = height;
    }
    
    @Override
    double area(){return 0.5 * base * height;}
}

public class Rectangle extends Shape{
    double length, width;
    Rectangle(double length, double width){
        this.length = length;
        this.width = width;
    }
    
    @Override
    double area(){return length * width;}
}

接著在main函式中宣告

public class Main{
    public static void main(String[] args){
        Circle cirlce = new Circle(3);
        Triangle triangle = new Triangle(4, 5);
        Rectangle rectangle = new Rectangle(6, 7);
        
        circle.display(); // 會顯示"This is a shape",是因為我們沒有在class中再override這個函式
        System.out.println(circle.area());
        System.out.println(triangle.area());
        System.out.println(rectangle.area());
    }
}

介面(interface)

而Interface就是pure abstract class,也就是完全抽象類別,無法用於建構出物件
在繼承interface的時候不再像繼承class那樣使用extends關鍵字,而是需要用 implements 這個關鍵字

interface中只需要宣告method的回傳值與名稱,且不需要再加abstract(因為interface已經定義了他就是abstract的)
對於一個class,可以同時繼承多個interface,且必須要 @Override 每一個interface裡面的method才能使用,否則compiler會報錯

首先定義一個名為Animal的parent class

public class Animal{
    String name;
    int age;
    
    Animal(String name, int age){
        this.name = name;
        this.age = age;
    }
    void eat(){
        System.out.println(this.name + " is eating");
    }
}

接著宣告兩個interface

public interface Flyable{
    void fly();
}

public interface Swimmalbe{
    vodi swim();
}

然後我們創建一個名為Duck的class,他屬於Animal,且同時會飛、會游泳

public class Duck extends Animal implements Flyable, Swimmable{
    Duck(String name, int age){
        super(name, age); // 用今天學到的super將資料傳回給parent class
    }
    
    // override interface的methods
    @Override
    void fly(){
        System.out.println(this.name + " is flying in the sky");
    }
    
    @Override
    void swim(){
        System.out.println(this.name + " is swimming in the water");
    }
    
    // 加上屬於Duck自己的函式
    void quack(){
        System.out.println(this.name + " says Quack!");
    }
}

最後在main函式中宣告Duck物件

public class Main{
    public static void main(String[] args){
        Duck donald = new Duck("Donald", 2);
        
        System.out.println("Name: " + donald.name);
        // Name: Donald
        System.out.println("Age: " + donald.age);
        // Age: 2
        donald.eat();
        // Donald is eating
        donald.fly();
        // Donald is flying in the sky
        donald.swim();
        // Donald is swimming in the water
        donald.quack();
        // Donald says Quack!
    }
}

結語

今天是接觸Java OOP的第二天,開始遇到一些理解上的問題了,以下是今天的提問與自我解答

  • 為什麼要分class和interface?
    一個class只能extends一個class,卻可以implements多個interface
    class用於解決is-a relationship的問題(是一種...),而implements用於解決has-a capability的問題(有...能力)
    分成這兩種可以在保證繼承的便利性的同時解決只能繼承一個class的問題

  • 那extends和implements在概念上又有什麼實質上的差距?
    extends是用於繼承,class繼承class,在保有parent class的意義的同時又可以額外增加自己的內容
    而implements是用於實現,class實現interface,讓一個class可以同時實現多個interface的內容,解決單一繼承的問題
    雖然用起來感覺只是對不同的名詞有不同的寫法,但實際上這是由於繼承的內容與目的的不同所導致的不同寫法

今天又是快樂學習的一天,明天繼續!/images/emoticon/emoticon71.gif


上一篇
Day 6:Java OOP基礎(一)
下一篇
Day 8:Java OOP基礎(三)
系列文
30天從基礎學起Java,直到做出我的第一個遊戲21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言